package org.quickjsf.core.base.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.quickjsf.common.util.DomainUtil;
import org.quickjsf.core.base.viewmodel.vo.FieldFilter;
import org.quickjsf.core.datamodel.HibernateFieldFilter;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;

@Component("absBaseDao")
public abstract class AbsBaseDao<T> extends HibernateDaoSupport implements IBaseDao<T>{
	
	@Resource
	public void setSuperSessionFactory(SessionFactory sessionFactory){
		super.setSessionFactory(sessionFactory);
	}
	
	public void delete(T entity) {
		getHibernateTemplate().delete(entity);
	}
	
	public void deleteAll(Collection<T> entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	public T queryById(Serializable id) {
		try {
			id = (Serializable) DomainUtil.getIdReturnType(typeClass()).getConstructor(String.class).newInstance(id);
			return getHibernateTemplate().get(typeClass(), id);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public T fetchAllById(final Serializable id) {
		return getHibernateTemplate().execute(new HibernateCallback<T>() {
			@SuppressWarnings("unchecked")
			@Override
			public T doInHibernate(Session session) throws HibernateException,
					SQLException {
				
				StringBuffer hsql = new StringBuffer();
				hsql.append("from ").append(typeClass().getSimpleName());
				hsql.append(" fetch all properties where ");
				hsql.append(DomainUtil.getIdHsql(typeClass(), id));
				return (T) session.createQuery(hsql.toString()).uniqueResult();
			}
		});
	}
	
	public List<T> queryAll() {
		return getHibernateTemplate().loadAll(typeClass());
	}
	
	public PageModel<T> queryTable(final int first, final int pageSize, final String sortField, final String sortName, final List<Criterion> criterions) {
		return getHibernateTemplate().execute(new HibernateCallback<PageModel<T>>() {
			@SuppressWarnings("unchecked")
			public PageModel<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(typeClass());
				PageModel<T> model = new PageModel<T>();
				
				//filters
			    if (null != criterions) {
			    	for (Criterion criterion : criterions) {
			    		criteria.add(criterion);
			    	}
			    }
			    //totalCount
				criteria.setProjection(Projections.rowCount());
				int totalCount = Integer.valueOf(criteria.uniqueResult().toString()); 
				model.setTotalCount(totalCount);
			    criteria.setProjection(null);

				//order
				if (null != sortField && null != sortName) {
					if (sortName.toLowerCase().equals("ascending")) {
						criteria.addOrder(Order.asc(sortField));
					} else if (sortName.toLowerCase().equals("descending")) {
						criteria.addOrder(Order.desc(sortField));
					} else {
						
					}
				}
				//Pagination
				criteria.setFirstResult(first);
				criteria.setMaxResults(pageSize);
				
				model.setDatas(criteria.list());
				return model;
			}
		});
	}
	@Override
	public PageModel<T> getTableFilterList(final int first, final int pageSize,
			final String sortField, final String sortName, final List<FieldFilter> fieldFilters) {
		
		try {
			return getHibernateTemplate().execute(new HibernateCallback<PageModel<T>>() {
				@SuppressWarnings("unchecked")
				public PageModel<T> doInHibernate(Session session) throws HibernateException,
						SQLException {
					Criteria criteria = session.createCriteria(typeClass());
					PageModel<T> model = new PageModel<T>();
					
					//filters
				    if (null != fieldFilters) {
				    	HibernateFieldFilter.setFilter(criteria, fieldFilters);
				    }
//				    totalCount
					criteria.setProjection(Projections.rowCount());
					int totalCount = Integer.valueOf(criteria.uniqueResult().toString()); 
					model.setTotalCount(totalCount);
				    criteria.setProjection(null);
				    //恢复默认的结果集状态
				    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 

					//order
					if (!StringUtils.isEmpty(sortField) && null != sortName) {
						if (sortName.toLowerCase().equals("ascending")) {
							criteria.addOrder(Order.asc(sortField));
						} else if (sortName.toLowerCase().equals("descending")) {
							criteria.addOrder(Order.desc(sortField));
						} else {
							
						}
					}
					//Pagination
					criteria.setFirstResult(first);
					criteria.setMaxResults(pageSize);
					
					model.setDatas(criteria.list());
					return model;
				}
			});
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
	
	public Serializable save(T entity) {
		return getHibernateTemplate().save(entity);
	}

	public void update(T entity) {
		getHibernateTemplate().update(entity);
	}
	//
    @SuppressWarnings("unchecked")  
    protected Class<T> typeClass() {  
        return (Class<T>) ((ParameterizedType) getClass()  
                .getGenericSuperclass()).getActualTypeArguments()[0];  
    } 
}
